/**
 * #info
 *
 *@author   wuwg
 *@createTime   2018/03/20
 *@updateTime   2018/06/19
 *@description  auto-complete  component 自动完成组件
 */

/**
 * #item
 *
 * @type        aty-auto-complete
 * @cn          自动完成
 * @menu        表单
 * @order         12
 * @stPlugin    true
 * @stContainer false
 * @children    [aty-option]
 * @mixins      [./components/components/form/form-item/form-item.js]
 */
import config from '../../../config/config.js'

// components
import Drop from '../../form/select/dropdown/index.vue'
import atyOption from '../select/option/index.vue'
import atyInput from '../input/index.vue'
// directives
import clickoutside from '../../../directives/clickoutside'
import TransferDom from '../../../directives/transfer-dom'
// mixins
import Emitter from '../../../mixins/emitter.js'
import formItem from '../form-item/form-item.js'
// prefix
const prefixCls = config.prefix + '-auto-complete'
// module
export default {
  name: prefixCls,
  mixins: [Emitter, formItem],
  components: { Drop, atyOption, atyInput },
  directives: { clickoutside, TransferDom },
  props: {
    /**
     * #property
     *
     * @name    value
     * @cn      搜索框中的值
     * @group   基本属性
     * @type    string,number
     * @description 搜索框中的值
     */
    value: {
      type: [String, Number],
      default: ''
    },
    /**
     * #property
     *
     * @name    data
     * @cn      特定的数据
     * @group   数据
     * @type    array
     * @bind    must
     * @description 特定的数据，用于静态查询
     */
    data: {
      type: Array,
      default: () => []
    },
    /**
     * #property
     *
     * @name    simple
     * @cn      是否是简单数据结构
     * @group   控制
     * @type    boolean
     * @value   true
     * @bind    must
     * @description 是否是简单数据结构，默认是，如果是简单数据的话，data的数据结构为 [String,String],
     *  如果不是简单数据，那么data的数据结构是 [{name:String},{name:String}]
     */
    simple: {
      type: Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name    clearable
     * @cn      是否有清除按钮
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 是否有清除按钮
     */
    clearable: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    notFoundText
     * @cn      当下拉列表为空时显示的内容
     * @group   基本属性
     * @type    string
     * @value   无匹配数据
     * @description 当下拉列表为空时显示的内容；
     */
    notFoundText: {
      type: String,
      default: '无匹配数据'
    },
    /**
     * #property
     *
     * @name    icon
     * @cn      图标
     * @group   基本属性
     * @type    icon
     * @description 输入框尾部图标
     */
    icon: {
      type: String
    },
    /**
     * #property
     *
     * @name    placement
     * @cn      下拉框出现的位置
     * @group   基本属性
     * @type    list
     * @options [top, bottom]
     * @value  bottom
     * @description 该下拉框出现的位置，取值为 ['top', 'bottom']中的其中一个
     */
    placement: {
      validator (value) {
        return Artery.isOneOf(value, ['top', 'bottom'])
      },
      default: 'bottom'
    },
    /**
     * #property
     *
     * @name    transfer
     * @cn      是否将弹层放置于 body 内
     * @group   控制
     * @type    boolean
     * @value  false
     * @description  是否将弹层放置于 body 内，
     *              在 Tabs、带有 fixed 的 Table 列内使用时，建议添加此属性，它将不受父级样式影响，从而达到更好的效果
     */
    transfer: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    elementId
     * @cn      input id
     * @group   基本属性
     * @type    string
     * @description 该输入框上的id
     */
    elementId: {
      type: String
    },
    /**
     * #property
     *
     * @name    remote
     * @cn      是否使用远程搜索
     * @group   远程搜索
     * @type    boolean
     * @value  false
     * @description 是否使用远程搜索；默认是远程搜索
     */
    remote: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    limit
     * @cn      限制条数
     * @group   基本属性
     * @type    number
     * @value   5
     * @bind   must
     * @description 限制查询的条数，默认是5条
     */
    limit: {
      type: Number,
      default: 5
    },
    /**
     * #property
     *
     * @name    delay
     * @cn      延迟（毫秒数）
     * @group   基本属性
     * @type    number
     * @value   500
     * @bind    must
     * @description 延迟查询，默认500毫秒
     */
    delay: {
      type: Number,
      default: 500
    },
    /**
     * #property
     *
     * @name    remoteMethod
     * @cn      远程搜索的方法
     * @group   远程搜索
     * @type    function
     * @bind    must
     * @description 远程搜索的方法；
     */
    remoteMethod: {
      type: Function // 注意这里这个要用的话必须是一个方法。
    },
    /**
     * #property
     *
     * @name    remoteUrl
     * @cn      远程搜索的url
     * @group   远程搜索
     * @type    string
     * @description 远程搜索的url；
     */
    remoteUrl: {
      type: String,
      default: ''
    },
    /**
     * #property
     *
     * @name    remoteExtendsParams
     * @cn      远程搜索的额外参数
     * @group   远程搜索
     * @type    object
     * @bind    must
     * @description 远程搜索的额外参数
     */
    remoteExtendsParams: {
      type: Object
    },
    /**
     * #property
     *
     * @name    pinyinSearch
     * @cn      是否支持拼音搜索
     * @group   控制
     * @type    boolean
     * @value  false
     * @description 是否支持拼音搜索,需要后台返回'fullSpell'（汉语拼音全拼）和'simpleSpell'（汉语拼音简拼）数据
     */
    pinyinSearch: {
      type: Boolean,
      default: false
    },
    /**
     * #property
     *
     * @name    emptyFilter
     * @cn      空文本是否触发过滤
     * @group   控制
     * @type	boolean
     * @bind    must
     * @value  true
     * @description 空文本是否触发过滤, 触发过滤将弹出下拉框
     */
    emptyFilter: {
      type:Boolean,
      default: true
    },
    /**
     * #property
     *
     * @name    dropdownWidth
     * @cn      下拉框宽度
     * @group   样式
     * @type    number
     * @bind    must
     * @description 如不指定和input保持一致, 指定为0则自适应内容宽度
     */
    dropdownWidth: {
      type: Number
    },
    /**
     * #property
     *
     * @name    dropDownMaxHeight
     * @cn      下拉数据区域最大高度
     * @group   样式
     * @type    number
     * @value   200
     * @bind    must
     * @description 超出最大高度显示滚动条
     */
    dropDownMaxHeight: {
      type: Number,
      default: 200
    }
  },
  data () {
    return {
      currentValue: this.value,
      currentData: [],
      visible: false,
      dropLoaded: false,
      notFound: false,
      // 性能优化，远程加载不能一直请求数据，所以设置了延迟
      // timerRemote: null
    }
  },
  watch: {
    value (val) {
      this.currentValue = val
    },
    currentValue (newValue, oldValue) {
      this.$emit('input', newValue)
      if (newValue) {
        this.filterData()
      } else {
        this.visible = false
      }
      // // 空值不触发过滤, 则需要做一些处理
      // if (!this.emptyFilter) {
      //   this.hideOrShowMenu(!!newValue)
      // }
      if (this.simple) {
        this.$emit('change', newValue)
      } else {
        const selectedObject = this.currentData.find(value => {
          // 还原name
          const _name = Artery.delHTMLTag(String(value.name))
          return _name === newValue
        })
        if (selectedObject) {
          this.$emit('change', selectedObject)
        } else {
          this.$emit('change', { id: '', name: newValue })
        }
      }
    },
    visible (newValue) {
      // 处理异步加载
      if (newValue && !this.dropLoaded) {
        this.dropLoaded = true
        this.$nextTick(() => {
          // 更新下拉框的位置
          this.broadcast(config.prefix + '-select-dropdown', 'update-popper')
        })
      }
    }
  },
  computed: {
    inputListeners: function () {
      const _this = this
      // `Object.assign` 将所有的对象合并为一个新对象
      return Object.assign({},
        // 从父级添加所有的监听器
        this.$listeners,
        // 自定义监听器，或覆写一些监听器的行为
        {
          iconclick: this.handleClear,
          focus: this.handleFocus,
          blur: this.handleBlur
        }
      )
    },
    inputAttrs: function () {
      return Object.assign({},
        // 默认属性
        {
          doValidate: false,
          icon: this.inputIcon
        },
        this.$attrs
      )
    },
    dropDownListStyles() {
      return {
        overflowY: 'auto',
        maxHeight: `${this.dropDownMaxHeight}px`
      }
    },
    warpClass () {
      return [
        prefixCls,
        {
          'not-data-item': this.currentData.length == 0
        }
      ].concat(this.formItemClasses)
    },
    // 下拉框的类名
    dropdownCls () {
      return [
        this.elementId ? prefixCls + this.elementId : '',
        {
          [prefixCls + '-dropdown-transfer']: this.transfer,
          // [config.prefix + '-auto-complete']: this.autoComplete
        }]
    },
    inputIcon () {
      let icon = ''
      if (this.clearable && this.currentValue) {
        icon = 'ios-close'
      } else if (this.icon) {
        icon = this.icon
      }
      return icon
    }
  },
  methods: {
    getValidateValue() {
      return this.currentValue
    },
    handleClose() {
      this.visible = false
    },
    // 获取焦点
    handleFocus () {
      /**
       * #event
       *
       * @name    focus
       * @param   value   当前的值
       * @param   name    当前值对应的name属性
       * @param   index   当前值对应的index属性
       * @body
       * @description focus聚焦事件
       */
      this.$emit('focus', this.currentValue)
      if (!this.currentValue && !this.emptyFilter) {
        return
      }
      //  过滤数据
      this.filterData()
    },
    // 失去焦点
    handleBlur () {
      /**
       * #event
       *
       * @name    blur
       * @param   value   当前的值
       * @param   name    当前值对应的name属性
       * @param   index   当前值对应的index属性
       * @body
       * @description blur失焦事件
       */
      this.$emit('blur', this.currentValue)
      this.handleClose()
      // if (this.oldValue === this.currentValue) {
      //   return
      // }
      this.validate()
    },
    clear () {
      this.currentValue = ''
    },
    // 清除按钮
    handleClear () {
      if (!this.clearable) {
        return
      }
      this.clear()
      /*
       * let changeItem = this.simple ? '' : null;
       * this.$emit('change', changeItem, this.name, this.index);
       */
      // this.dispatchValidateEvent()
      this.validate()
    },
    // change事件
    handleChange (value) {
      let item = value
      if (value == '' && !this.simple) {
        item = {
          name: '',
          id: ''
        }
      }
      // 还原name
      const _name = Artery.delHTMLTag(this.simple ? String(item) : String(item.name))
      let changeItem = null
      if (this.simple) {
        changeItem = _name
      } else {
        //  如果是对象的话，需要还原item中的name
        item.name = _name
        changeItem = item
      }
      // 当前值
      this.currentValue = _name
      /*
       *  原因是 this.$refs.input 指向了 aty-input组件，  $refs.input 才能指向 aty-input中的 input
       * this.$refs.input.$refs.input.blur(); // 已经blur过了
       */
      // /**
      //  * #event
      //  *
      //  * @name    choose
      //  * @param   value   当前的值
      //  * @param   name    当前值对应的name属性
      //  * @param   index   当前值对应的index属性
      //  * @body
      //  * @description 选择下拉搜索的项触发
      //  */
      this.$emit('choose', changeItem)
      // this.$emit('change', changeItem, this.name, this.index);
      // this.dispatchValidateEvent()
      this.validate()
      this.$nextTick(() => this.visible = false)
    },
    // 设置当前数据
    setCurrentData (data) {
      let _data = data
      // 判断数据的长度
      if (_data.length > this.limit) {
        _data = _data.slice(0, this.limit)
      }
      // 赋值
      this.currentData = _data
      this.notFound = !_data || data.length == 0
    },
    // 过滤数据
    filterData () {
      // 非远程,就调用内置的过滤,否则获取远程数据
      (!this.remote) ? this.inlayFilterMethod() : this.getRemoteData(this.currentValue)
      this._oldFilteredValue = this.currentValue // 用于判断值没变不再重新过滤
    },
    // 内置过滤数据的方法
    inlayFilterMethod () {
      // 转
      let _newData = JSON.parse(JSON.stringify(this.data))
      // 文字高亮
      _newData = this.patternLightWord(_newData)
      // 设置当前数据
      this.setCurrentData(_newData)
      this.showDrop()
    },
    // 文字高亮
    patternLightWord (_newData) {
      // 当搜索的值不为空字符串时
      if (this.currentValue) {
        // 数据匹配度排序：完全匹配在前 + 部分匹配在后
        // 1、全匹配
        var _equalsData = []
        _newData = this.simple ?
            _newData.reduce((data, item) => {
                // 如果匹配成功
                if (this.currentValue === item) {
                    _equalsData.push(String(item).replace(this.currentValue, (target) => `<em>${target}</em>`))
                } else {
                    data.push(item)
                }
                return data;
            }, []) :
            _newData.reduce((data, item) => {
                // 如果匹配成功
                if (this.currentValue === item.name || this.pinyinEquals(item)) {
                    item.name = String(item.name).replace(this.currentValue, (target) => `<em>${target}</em>`);
                    // 添加到数组中
                    _equalsData.push(item);
                } else {
                    data.push(item)
                }
                return data;
            }, []);

        // 2、部分匹配 正则
        var _matchData = []
        const pattern = new RegExp(this.currentValue.replace(/(\^|\(|\)|\[|\]|\$|\*|\+|\.|\?|\\|\{|\}|\|)/g, '\\$1'), 'igm');
        //  过滤数组,分简单数据和复杂数据结构
        _matchData = this.simple ?
            _newData.reduce((data, item) => {
                // 如果匹配成功
                if (pattern.test(String(item))) {
                    data.push(String(item).replace(pattern, (target) => `<em>${target}</em>`))
                }
                return data;
            }, []) :
            _newData.reduce((data, item) => {
                // 如果匹配成功
                if (pattern.test(String(item.name)) || this.pinyinMatch(item)) {
                    item.name = String(item.name).replace(pattern, (target) => `<em>${target}</em>`);
                    // 添加到数组中
                    data.push(item);
                }
                return data;
            }, []);
        return _equalsData.concat(_matchData)
      } else if (this.emptyFilter) { // 清空了currentValue, 则清空高亮状态
        return this.simple ?
          _newData.reduce((data, item) => {
            data.push(Artery.delHTMLTag(String(item)))
            return data
          }, []) :
          _newData.reduce((data, item) => {
            item.name = Artery.delHTMLTag(String(item.name))
            data.push(item)
            return data
          }, [])
      }  else {
        return _newData
      }
    },
    // 判断拼音简拼或全拼是否匹配
    pinyinMatch (item) {
      if (this.pinyinSearch && item) {
        if (item.fullSpell && item.fullSpell.toLowerCase().indexOf(this.currentValue.toLowerCase()) != -1) {
          return true
        }
        if (item.simpleSpell && item.simpleSpell.toLowerCase().indexOf(this.currentValue.toLowerCase()) != -1) {
          return true
        }
      }
      return false
    },
    // 拼音全匹配
    pinyinEquals(item){
        if(this.pinyinSearch && item){
            if(item.fullSpell && item.fullSpell.toLowerCase() === this.currentValue.toLowerCase()){
                return true;
            }
            if(item.simpleSpell && item.simpleSpell.toLowerCase() === this.currentValue.toLowerCase()){
                return true;
            }
        }
        return false;
    },
    remoteCallback (_newData) {
      _newData = this.patternLightWord(_newData)
      this.setCurrentData(_newData)
      // 更新下拉框位置
      this.broadcast(config.prefix + '-select-dropdown', 'update-popper')
      if (this._clickOption) {
        this._clickOption = false
      } else {
        this.showDrop()
      }
    },
    getRemoteData: function (query) {
      // 性能优化
      if (this.timerRemote) {
        clearTimeout(this.timerRemote)
      }
      // 防抖函数
      this.timerRemote = setTimeout(() => {
        // 先判断用户是否自己写了请求数据的方法
        if (Artery.type(this.remoteMethod) == 'function') {
          this.remoteMethod(query, this.remoteCallback)
        } else {
          // 请求远程数据的方法
          this.requestRemoteData(query, this.remoteCallback)
        }
      }, this.delay)
    },
    // 请求远程数据的方法
    requestRemoteData (query, callback) {
      // 那么必须先指定url(远程搜索的url)
      if (this.remoteUrl) {
        // 请求参数, 合并参数 （远程搜索的额外参数）
        const _params = Object.assign({ query: query || '' }, this.remoteExtendsParams || {})
        Artery.ajax.get(this.remoteUrl, { params: _params }).then(function (data) {
          // 执行回调函数
          callback(data)
        })
      } else {
        console.error('必须指定远程所有地址：remoteUrl')
      }
    },
    showDrop() {
      if (this.emptyFilter || this.currentValue) {
        this.visible = true
      }
    },
    select (value) {
      this._clickOption = true
      if (this.simple) {
        if (Artery.type(value) === 'string') {
          value = Artery.delHTMLTag(value)
        }
        this.currentValue = value
      } else {
        this.currentValue = Artery.delHTMLTag(value.name)
      }
      this.handleChange(value)
    },
    delHTMLTag (text) {
      return Artery.delHTMLTag(String(text))
    }
  },
  mounted () {
    this.setCurrentData(this.data)
    this.$on('select-selected', (value) => {
      // 如果是点选的情况, 不需要请求服务器了, 强制从本地下拉候选项搜索就行了
      // this._clickOption = true
      // if (this.simple) {
      //   if (Artery.type(value) === 'string') {
      //     value = Artery.delHTMLTag(value)
      //   }
      //   this.currentValue = value
      // } else {
      //   this.currentValue = Artery.delHTMLTag(value.name)
      // }
      // this.handleChange(value)
    })
  },
  beforeDestroy() {
    this.$off('select-selected')
  }
}
